﻿using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 条形码生成与识别
{
    public class Code
    {
        /// <summary>
        /// 获取数字字符二进制编码
        /// </summary>
        /// <param name="type">编码类型:0:A方式,1:B方式,2:C方式</param>
        /// <param name="num">数字字符:0到9</param>
        /// <returns></returns>
        public byte[] GetCode(int type,int num)
        {
            byte[,][] code = new byte[3,10][];
            //A编码
            code[0, 0] = new byte[] { 0,0,1,1,0,0,1 };
            code[0, 1] = new byte[] { 0,0,1,1,0,0,1 };
            code[0, 2] = new byte[] { 0,0,1,0,0,1,1 };
            code[0, 3] = new byte[] { 0,1,1,1,1,0,1 };
            code[0, 4] = new byte[] { 0,1,0,0,0,1,1 };
            code[0, 5] = new byte[] { 0,1,1,0,0,0,1 };
            code[0, 6] = new byte[] { 0,1,0,1,1,1,1 };
            code[0, 7] = new byte[] { 0,1,1,1,0,1,1 };
            code[0, 8] = new byte[] { 0,1,1,0,1,1,1 };
            code[0, 9] = new byte[] { 0,0,0,1,0,1,1 };
            //B编码
            code[1, 0] = new byte[] { 0,1,0,0,1,1,1 };
            code[1, 1] = new byte[] { 0,1,1,0,0,1,1 };
            code[1, 2] = new byte[] { 0,0,1,1,0,1,1 };
            code[1, 3] = new byte[] { 0,1,0,0,0,0,1 };
            code[1, 4] = new byte[] { 0,0,1,1,1,0,1 };
            code[1, 5] = new byte[] { 0,1,1,1,0,0,1 };
            code[1, 6] = new byte[] { 0,0,0,0,1,0,1 };
            code[1, 7] = new byte[] { 0,0,1,0,0,0,1 };
            code[1, 8] = new byte[] { 0,0,0,1,0,0,1 };
            code[1, 9] = new byte[] { 0,0,1,0,1,1,1 };
            //C编码
            for (int i = 0; i < 10; i++)
            {
                byte[] temp = new byte[7];
                Array.Copy( code[1, i],temp,temp.Length);
                Array.Reverse(temp);
                code[2, i] = temp;
            }
            return code[type,num];
        }
        /// <summary>
        /// 获取编码方式
        /// </summary>
        /// <param name="forword">前置码</param>
        /// <returns>长度为6的编码方式数组，其中0为A方式，1为B方式</returns>
        public  byte[] GetCodeChose(int prefix)
        {
            byte[][] chose = new byte[10][];
            //编码方式选择.0为A方式，1为B方式
            chose[0] = new byte[] { 0, 0, 0, 0, 0, 0 };
            chose[1] = new byte[] { 0, 0, 1, 0, 1, 1 };
            chose[2] = new byte[] { 0, 0, 1, 1, 0, 1 };
            chose[3] = new byte[] { 0, 0, 1, 1, 1, 0 };
            chose[4] = new byte[] { 0, 1, 0, 0, 1, 1 };
            chose[5] = new byte[] { 0, 1, 1, 0, 0, 1 };
            chose[6] = new byte[] { 0, 1, 1, 1, 0, 0 };
            chose[7] = new byte[] { 0, 1, 0, 1, 0, 1 };
            chose[8] = new byte[] { 0, 1, 0, 1, 1, 0 };
            chose[9] = new byte[] { 0, 1, 1, 0, 1, 0 }; 
            return chose[prefix];
        }
        /// <summary>
        /// 获取校验位
        /// </summary>
        /// <param name="str">十进制编码字符串</param>
        /// <returns>校验位值</returns>
        public int GetCheckBit(string str)
        {
            int[] num = ConvertToIntArray(str);
            int sum = 0;
            for(int i = 1; i < 13; i++)
            {
                if (i % 2 == 0)
                    sum += num[i-1] * 3;
                else
                    sum += num[i-1];
            }
            if (sum % 10 == 0)
                return 0;
            return 10 - sum % 10;
        }
        /// <summary>
        /// string转为int数组
        /// </summary>
        /// <param name="str">要转化的字符串</param>
        /// <returns>一个int型数组</returns>
        public static int[] ConvertToIntArray(string str)
        {
            char[] c = str.ToCharArray();
            int[] num = new int[str.Length];
            for (int i = 0; i < str.Length; i++)
            {
                num[i] = Convert.ToInt32(c[i].ToString());
            }
            return num;
        }
        /// <summary>
        /// 生成条形码
        /// </summary>
        /// <param name="text">十进制编码字符串</param>
        /// <param name="code">二进制编码字符串</param>
        /// <param name="minWidth">一个模块的最小宽度(单位:px)</param>
        /// <param name="height">图像高度</param>
        /// <returns>条形码图像</returns>
        public Image<Gray,byte> DrawCode(string text,string code, int minWidth,int height)
        {
            int w = minWidth * 113;
            int[] num = ConvertToIntArray(text+GetCheckBit(text));
            Image<Gray, byte> img = new Image<Gray, byte>(new Size(w,height)).Not();
            int[] bit = ConvertToIntArray(code);
            int margin = minWidth * 9;
            for(int i = 0; i < bit.Length; i++)
            {
                int x = i * minWidth + margin;
                int y1 = margin;
                int y2 = height - margin;
                if (bit[i] == 1)
                {
                    if (i < 3)
                    {
                        y2= height - margin + height / 15;
                    }
                    if(i>44&&i<50)
                    {
                        y2= height - margin + height / 15; 
                     
                    }
                    if(i>91&&i<95)
                    {
                        y2= height - margin + height / 15;
                    }
                    img.Draw(new LineSegment2D(new Point(x, y1), new Point(x, y2)), new Gray(0), minWidth);
                  
                }
            }
            img.Draw(num[0].ToString(), new Point(0 * minWidth * 7 + minWidth * 3, height - margin + height / 7), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 3.0, new Gray(0), 5);
            for (int i = 1; i < num.Length; i++)
            {
                img.Draw(num[i].ToString(), new Point(i * minWidth*7 + margin, height - margin + height / 7), Emgu.CV.CvEnum.FontFace.HersheyComplexSmall, 3.0, new Gray(0),5);
            }
            return img;
        }
        /// <summary>
        /// 获取国家名
        /// </summary>
        /// <param name="num">国家代号</param>
        /// <returns>国家名称</returns>
        public static string GetCountry(int num)
        {
            Dictionary<int,string> dir = new Dictionary<int, string>();
             string[] countrys = File.ReadAllLines("countries.txt",Encoding.UTF8);
            foreach(string s in countrys)
            {
                dir.Add(Convert.ToInt32(s.Split(' ')[0]), s.Split(' ')[1]);
            }
            if (!dir.ContainsKey(num))
                throw new Exception("国家代码错误，不符合EAN-13标准!");
            return dir[num];
        }
    }
}
